#include "Server.h"
#include <boost/thread.hpp>
#include <boost/bind.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/lexical_cast.hpp>
#include <vector>

namespace bip = boost::asio::ip;

Server::Server(const std::string &port,std::size_t thread_pool_size) :  myThreadPoolSize(thread_pool_size),
																	    myAcceptor(myIO_service),
																	    myNewConnection(new SRVConnection(myIO_service,&myReceived))
{
	bip::tcp::endpoint aEndpoint(bip::tcp::v4(),boost::lexical_cast<short>(port));
	myAcceptor.open(aEndpoint.protocol());
	boost::asio::socket_base::keep_alive keep_option(true);
	myAcceptor.set_option(bip::tcp::acceptor::reuse_address(true));
	myAcceptor.set_option(keep_option);
	myAcceptor.bind(aEndpoint);
	myAcceptor.listen();
	myAcceptor.async_accept(myNewConnection->GetSocket(),boost::bind(&Server::handle_accept,this,boost::asio::placeholders::error));
}


void Server::Run()
{
	std::vector<boost::shared_ptr<boost::thread> > aThreads;
	for(std::size_t i=0; i < myThreadPoolSize; ++i)
	{
		boost::shared_ptr<boost::thread> thread(new boost::thread(boost::bind(&boost::asio::io_service::run,&myIO_service)));
		aThreads.push_back(thread);
	}

	for(std::size_t i=0; i < aThreads.size(); ++i)
		aThreads[i]->join();
}


void Server::Stop()
{
	myIO_service.stop();
}

void Server::handle_accept(const boost::system::error_code &er)
{
	if(!er)
	{
		myNewConnection->Start();
		myNewConnection.reset(new SRVConnection(myIO_service,&myReceived));
		myAcceptor.async_accept(myNewConnection->GetSocket(),boost::bind(&Server::handle_accept,this,boost::asio::placeholders::error));
	}
}

boost::optional<boost::shared_ptr<Data> > Server::GetReceived()
{
	boost::mutex::scoped_lock lock(myMutex);

	if(myReceived.size() > 0)
	{
		boost::shared_ptr<Data> aReceived = myReceived.front();
		myReceived.pop();
		return boost::optional<boost::shared_ptr<Data> >(aReceived);
	}

	return boost::optional<boost::shared_ptr<Data> >(); //prazdna kolekcia 
}

/*
void Server::handle_received(DataContainer receivedContainer)
{
	boost::mutex::scoped_lock lock(myMutex);

	myReceived.push(receivedContainer);
}
*/